


function ReportQuery(query) {
	this.id			= (new Date()).getTime();
	this.query		= query;
	this.paramHandles	= new Object();
	this.variableHandles	= new Object();
	this.variables		= new Object();

	//Used when template contains two or more queries with the same title
	this.hasBeenLoaded	= false;

	this.init = function() {


		for (paramName in this.query.params) {

			var paramType = this.query.params[paramName];
			var realParamType = paramType;
			if (paramType & SELECT_MULTIPLE) {
				realParamType = paramType - 1;
			}

			EventHandler.addListener("addvar", {"type":realParamType}, this.addVariable.bind(this));
			EventHandler.addListener("remvar", {"type":realParamType}, this.removeVariable.bind(this));

			this.paramHandles[paramName] 	= new Array();
			this.variableHandles[paramName] = new Array();
			this.variables[paramName] 	= null;
		}



	}

	this.addParamHandle = function(paramName, handle) {
		this.paramHandles[paramName].push(handle);

		var variableHandle = this.createVariableSelector(handle, paramName);
		if (variableHandle) {
			this.variableHandles[paramName].push(variableHandle);
		}
	}

	this.removeParamHandle = function(paramName, handle) {
		for (var i=0; i<this.paramHandles[paramName].length; i++) {
			if (this.paramHandles[paramName][i] == handle) {

				//Remove variable selector
				if (this.variables[paramName] != null) {
					var variableSelector = this.variableHandles[paramName][i];
					var div = variableSelector.parentNode;
					var container = div.parentNode;
					container.removeChild(div);
				}

				this.paramHandles[paramName].splice(i, 1);
				this.variableHandles[paramName].splice(i, 1);
				return;
			}
		}
	}

	this.addVariable = function(props) {

		var paramName = getParamNameFromDefinition(this.query, props.type);

		var create = false;
		if (this.variables[paramName] == null) {
			create = true;
			this.variables[paramName] = new Array();
		}

		this.variables[paramName].push(props.name);

		if (create) {
			//Create a new selector for each handle
			for (var i=0; i<this.paramHandles[paramName].length; i++) {
				var container = this.paramHandles[paramName][i];
				var variableHandle = this.createVariableSelector(container, paramName);
				this.variableHandles[paramName][i] = variableHandle;
			}
		} else {
			//Just add option for each handle
			for (var i=0; i<this.variableHandles[paramName].length; i++) {
				var newOption = new Option(props.name, props.name);
				this.variableHandles[paramName][i].appendChild(newOption);
			}
		}
	}

	this.removeVariable = function(props) {

		var paramName = getParamNameFromDefinition(this.query, props.type);

		if (this.variables[paramName] != null) {
			for (var i=0; i<this.variables[paramName].length; i++) {
				if (this.variables[paramName][i] == props.name) {
					this.variables[paramName].splice(i, 1);
					break;
				}
			}

			//Remove option from all selectors
			for (var i=0; i<this.variableHandles[paramName].length; i++) {
				var variableSelector = this.variableHandles[paramName][i];
				for (var j=0; j<variableSelector.options.length; j++) {
					if (variableSelector.options[j].value == props.name) {
						variableSelector.remove(j);
						j--;
					}
				}
			}


			if (this.variables[paramName].length == 0) {

				//Remove all selectors
				for (var i=0; i<this.variableHandles[paramName].length; i++) {
					var variableSelector = this.variableHandles[paramName][i];

					var div = variableSelector.parentNode;
					var container = div.parentNode;

					//Make sure all inputs etc are enables
					enableNodesOfType(container, new Array("input", "select"), true, null);

					container.removeChild(div);
				}

				this.variableHandles[paramName] = new Array();
				this.variables[paramName] = null;

			} else {

				//Make sure that inputs etc are enabled if 'no variable' option is selected
				for (var i=0; i<this.variableHandles[paramName].length; i++) {
					var variableSelector = this.variableHandles[paramName][i];

					var container = variableSelector.parentNode.parentNode;
					enableNodesOfType(container, new Array("input", "select"), (variableSelector.selectedIndex==0), "variable-selector");
				}

			}
		}

	}

	this.createVariableSelector = function(container, paramName) {
		if (this.variables[paramName] == null) {
			return false;
		}


		var div = document.createElement("div");
		div.style.marginBottom = "10px";
		container.appendChild(div);


		var infoSpan = document.createElement("span");
		infoSpan.appendChild(document.createTextNode("or use variable: "));
		div.appendChild(infoSpan);



		var selector = document.createElement("select");
		selector.className = "variable-selector";

		//'No variable' -option
		var opt = document.createElement("option");
		opt.value = "null";
		opt.appendChild(document.createTextNode("<no variable>"));
		selector.appendChild(opt);

		for (var i=0; i<this.variables[paramName].length; i++) {
			selector.options[i+1] = new Option(this.variables[paramName][i], this.variables[paramName][i]);
		}
		div.appendChild(selector);

		Event.observe(selector, "change", this.clickChangeVariableSelector.bindAsEventListener(this));

		return selector;
	}

	this.setVariable = function(selector) {
		var newVariable = selector.options[selector.options.selectedIndex].value;
		var container = selector.parentNode.parentNode;

		//Recursively disable input and select nodes
		enableNodesOfType(container, new Array("input", "select"), (newVariable == "null"), "variable-selector");
	}

	this.setVariables = function(paramName, values) {
		for (var i=0; i<this.paramHandles[paramName].length; i++) {
			if (values[i]) {
				if (getVariableByName(values[i])) {
					var selector = this.variableHandles[paramName][i];
					if (selector) {
						var newSelect = selectOption(selector, values[i]);
						if (newSelect) {
							var container = selector.parentNode.parentNode;

							//Recursively disable input and select nodes
							enableNodesOfType(container, new Array("input", "select"), false, "variable-selector");
						}
					}
				} else {
					showError("\""+values[i]+"\" is not a valid variable!");
				}
			}
		}
	}

	this.clickChangeVariableSelector = function(evt) {
		var selector = Event.findElement(evt);
		this.setVariable(selector);
	}

	this.getParamHandleCount = function(paramName) {
		return this.paramHandles[paramName].length;
	}

	this.setParam = function(paramName, values) {
		var paramType = this.query.params[paramName];
		if (this.paramHandles[paramName]) {
			for (var i=0; i<values.length; i++) {

				if ( (i>0) && (!(paramType & SELECT_MULTIPLE)) ) {
					//No need to go on
					return;
				}

				//Create param if it does not exist
				if ( (!this.paramHandles[paramName][i]) && (this.paramHandles[paramName][0]) ) {

					var parent = this.paramHandles[paramName][0].parentNode;

					if (typeof(paramType) == "object") {

						//Enumerable
						//This is just a select element, no need to add anything more

					} else if (paramType & TYPE_DATERANGE) {

						//Date Range
						var typeContainer = addDateRange(parent, true, null);
						this.addParamHandle(paramName, typeContainer);

					} else if (paramType & TYPE_DATE) {

						//Single Date
						var typeContainer = addDate(parent, true, null);
						this.addParamHandle(paramName, typeContainer);

					} else if ( (paramType & TYPE_INT) || (paramType & TYPE_FLOAT) || (paramType & TYPE_STRING) ) {

						//Primitive
						var typeContainer = addPrimitive(parent, true, null);
						this.addParamHandle(paramName, typeContainer);

					} else {

						//A user-defined type
						//This is just a select element, no need to add anything more

					}

				}



				//Set parameter

				if (typeof(paramType) == "object") {

					//Enumerable

					//Fetch first child, should be the select element
					var selector = this.paramHandles[paramName][i].firstChild;
					selectOption(selector, values[i]);

				} else if (paramType & TYPE_DATERANGE) {

					//Date Range
					setDateRangeValue(this.paramHandles[paramName][i], values[i].trim());

				} else if (paramType & TYPE_DATE) {

					//Single Date
					setDateValue(this.paramHandles[paramName][i], values[i].trim());

				} else if ( (paramType & TYPE_INT) || (paramType & TYPE_FLOAT) || (paramType & TYPE_STRING) ) {

					//Primitive

					//Fetch first child, should be the input fields
					var input = this.paramHandles[paramName][i].firstChild;
					input.value = values[i];

				} else {

					//A user-defined type

					//Fetch first child, should be the select element
					var selector = this.paramHandles[paramName][i].firstChild;
					selectOption(selector, values[i]);

				}

			}
		}
	}

	this.toXML = function(tab) {
		var xml = "";
		xml += tab+"<query title=\""+this.query.title+"\">\n";

		for (paramName in this.paramHandles) {

			//What kind of param is this?
			var paramType = this.query.params[paramName];
			var realParamType = paramType;
			if (paramType & SELECT_MULTIPLE)
				realParamType = paramType - 1;

			var typeLabel = typeLookup[realParamType];
			if (!typeLabel)
				typeLabel = paramType; //Enumerable

			xml += tab+"\t<param name=\""+paramName+"\" type=\""+typeLabel+"\">\n";

			for (var i=0; i<this.paramHandles[paramName].length; i++) {

				//First see if a variable is used
				var usesVariable = false;
				if (this.variables[paramName] != null) {
					var selector 	= this.variableHandles[paramName][i];
					var selectedVal = selector.options[selector.selectedIndex].value;
					if (selectedVal != "null") {
						usesVariable = true;
						xml += tab+"\t\t<value uses-variable=\""+selectedVal+"\">\n";
						xml += tab+"\t\t</value>\n";
					}
				}


				if (!usesVariable) {

					//No variable is used, parse value from DOM
					var currentNode = this.paramHandles[paramName][i];

					var value = null;

					//Parse value according to type
					if (paramType & TYPE_DATERANGE) {
						value = getDateRangeString(currentNode);

					} else if (paramType & TYPE_DATE) {
						value = getDateString(currentNode);

					} else if ( (paramType & TYPE_INT) || (paramType & TYPE_FLOAT) || (paramType & TYPE_STRING) ) {
						value = getPrimitiveString(currentNode);

					} else {

						//Enumerable or user-defined type
						var selector = currentNode.firstChild;
						for (var i=0; i<selector.options.length; i++) {
							if (selector.options[i].selected) {
								xml += tab+"\t\t<value>\n";
								xml += tab+"\t\t\t"+selector.options[i].value+"\n";
								xml += tab+"\t\t</value>\n";
							}
						}

					}

					if (value) {
						xml += tab+"\t\t<value>\n";
						xml += tab+"\t\t\t"+value+"\n";
						xml += tab+"\t\t</value>\n";
					}
				}

			}

			xml += tab+"\t</param>\n";
		}

		xml += tab+"</query>\n";

		return xml;
	}

	this.init();
}



function resetQueryLoadedStatus() {
	for (var i=0; i<reportQueries.length; i++) {
		reportQueries[i].hasBeenLoaded = false;
	}
}


function getReportQueryById(id) {
	for (var i=0; i<reportQueries.length; i++) {
		if (reportQueries[i].id == id) {
			return reportQueries[i];
		}
	}
}


function getReportQueryByTitle(title) {
	for (var i=0; i<reportQueries.length; i++) {
		if ( (reportQueries[i].query.title == title) && (!reportQueries[i].hasBeenLoaded) ) {
			reportQueries[i].hasBeenLoaded = true;
			return reportQueries[i];
		}
	}
}


function getReportQueryFromElement(elm) {
	while (elm) {
		if (elm.className) {
			if (elm.className.indexOf("subreport")!=-1) {
				break;
			}
		}
		elm = elm.parentNode;
	}
	var id = elm.getAttribute("id");
	return getReportQueryById(id);
}


function removeQuery(evt) {
	var rq = getReportQueryFromElement(Event.findElement(evt));
	$("report_container").removeChild($(""+rq.id));

	for (var i=0; i<reportQueries.length; i++) {
		if (reportQueries[i] == rq) {
			reportQueries.splice(i, 1);
			return;
		}
	}
}


function renderQuery(rq, parent) {

	var container = document.createElement("div");
	container.className = "content_table subreport";
	container.setAttribute("id", rq.id);

	//Render title row
	var titleTable 	= document.createElement("table");
	var titleTbody 	= document.createElement("tbody");
	var tr 		= document.createElement("tr");
	var tdTitle 	= document.createElement("td");
	var tdActions 	= document.createElement("td");
	tr.appendChild(tdTitle);
	tr.appendChild(tdActions);
	titleTbody.appendChild(tr);
	titleTable.appendChild(titleTbody);

	titleTable.className = "table_header";

	//First column
	var titleElm = document.createElement("h3");
	titleElm.appendChild(document.createTextNode(rq.query.title));
	tdTitle.appendChild(titleElm);

	//Second column
	tdActions.style.textAlign = "right";
	var removeHref = document.createElement("a");
	removeHref.href = "javascript:;";
	var removeImg = document.createElement("img");
	removeImg.src = "img/silk/delete.png";
	removeImg.style.border = "0px";
	removeImg.style.marginRight = "6px";
	removeHref.appendChild(removeImg);
	removeHref.appendChild(document.createTextNode("Remove"));
	tdActions.appendChild(removeHref);
	Event.observe(removeHref, "click", removeQuery);



	//Render parameters
	var table = document.createElement("table");
	var tbody = document.createElement("tbody");

	for (paramName in rq.query.params) {
		var tr = document.createElement("tr");
		var tdName = document.createElement("td");
		var tdData = document.createElement("td");

		//Parameter name
		tdName.vAlign = "top";
		tdName.appendChild(document.createTextNode(paramName));

		//Parameter data
		var paramType = rq.query.params[paramName];
		tdData.setAttribute("name", paramName);


		var typeContainer;

		if (typeof(paramType) == "object") {

			//Enumerable
			var selector = document.createElement("select");
			for (var i=0; i<paramType.length; i++) {
				selector.options[i] = new Option(paramType[i], paramType[i]);
			}
			tdData.appendChild(selector);
			typeContainer = tdData;

		} else if (paramType & TYPE_DATERANGE) {

			//Date Range

			if (paramType & SELECT_MULTIPLE) {
				renderAdd(tdData, addDateRangeClick);
			}
			typeContainer = addDateRange(tdData, !(paramType & SELECT_MULTIPLE), null);

		} else if (paramType & TYPE_DATE) {

			//Single Date

			if (paramType & SELECT_MULTIPLE) {
				renderAdd(tdData, addDateClick);
			}
			typeContainer = addDate(tdData, !(paramType & SELECT_MULTIPLE), null);

		} else if ( (paramType & TYPE_INT) || (paramType & TYPE_FLOAT) || (paramType & TYPE_STRING) ) {

			//Primitive

			if (paramType & SELECT_MULTIPLE) {
				renderAdd(tdData, addPrimitiveClick);
			}
			typeContainer = addPrimitive(tdData, !(paramType & SELECT_MULTIPLE), null);

		} else {

			//A user-defined type

			var selector = document.createElement("select");

			var realParamType = paramType;
			if (paramType & SELECT_MULTIPLE) {
				realParamType = paramType - SELECT_MULTIPLE;
				selector.size = "5";
				selector.multiple = "multiple";
			}

			var values = fillType(realParamType);
			var i=0;
			for (id in values) {
				selector.options[i] = new Option(values[id], id);
				i++;
			}
			tdData.appendChild(selector);
			typeContainer = tdData;

		}

		rq.addParamHandle(paramName, typeContainer);


		tr.appendChild(tdName);
		tr.appendChild(tdData);
		tbody.appendChild(tr);
	}

	container.appendChild(titleTable);
	table.appendChild(tbody);
	container.appendChild(table);
	parent.appendChild(container);
}


function addQuery(title) {
	var query = getQueryByTitle(title);
	var rq = new ReportQuery(query);

	renderQuery(rq, $("report_container"));

	reportQueries.push(rq);
}


function addQueryClick(evt) {
	//Which query is focused?
	var title = $("querySelector").options[$("querySelector").options.selectedIndex].value;
	addQuery(title);
}


